package version

import (
	"crypto/tls"
	"fmt"
	"net/http"
	"net/url"
	"os/exec"
	"regexp"
	"sort"
	"strconv"
	"strings"
	"time"

	"github.com/PuerkitoBio/goquery"
	"go.uber.org/zap"
)


// VersionInfo 版本信息结构体
// 示例值: Version="9.7p1", DownloadURL="https://mirrors.aliyun.com/openssh/portable/openssh-9.7p1.tar.gz"
type VersionInfo struct {
	Version     string // 版本号
	DownloadURL string // 下载URL
	Filename    string // 文件名
}

// Detector 版本检测器
// 示例值: mirrorURL="https://mirrors.aliyun.com/openssh/portable/"
type Detector struct {
	mirrorURL      string
	client         *http.Client
	skipTLSVerify  bool
}

// NewDetector 创建版本检测器
// 示例值: mirrorURL="https://mirrors.aliyun.com/openssh/portable/"
func NewDetector(mirrorURL string, skipTLSVerify bool) *Detector {
	detector := &Detector{
		mirrorURL:     mirrorURL,
		skipTLSVerify: skipTLSVerify,
	}
	
	// 创建HTTP客户端
	detector.client = detector.createHTTPClient()
	
	return detector
}

// createHTTPClient 创建HTTP客户端
// 示例值: 无参数
func (d *Detector) createHTTPClient() *http.Client {
	client := &http.Client{
		Timeout: 30 * time.Second,
		Transport: &http.Transport{
			MaxIdleConns:        10,
			IdleConnTimeout:    30 * time.Second,
			DisableCompression: true,
		},
	}
	
	// 如果启用跳过TLS证书验证
	if d.skipTLSVerify {
		transport := client.Transport.(*http.Transport).Clone()
		transport.TLSClientConfig = &tls.Config{
			InsecureSkipVerify: true,
		}
		client.Transport = transport
		zap.L().Info("版本检测器已启用跳过HTTPS证书检测模式")
	}
	
	return client
}

// GetLatestVersion 获取最新版本信息
// 示例值: 无参数
func (d *Detector) GetLatestVersion() (*VersionInfo, error) {
	zap.L().Info("开始检测OpenSSH最新版本")

	// 发送HTTP请求获取镜像页面
	req, err := http.NewRequest("GET", d.mirrorURL, nil)
	if err != nil {
		return nil, fmt.Errorf("创建HTTP请求失败: %v", err)
	}

	req.Header.Set("User-Agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36")

	resp, err := d.client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("HTTP请求失败: %v", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("HTTP请求失败，状态码: %d", resp.StatusCode)
	}

	// 使用goquery解析HTML
	doc, err := goquery.NewDocumentFromReader(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("解析HTML失败: %v", err)
	}

	// 查找所有.tar.gz文件链接
	var tarFiles []string
	doc.Find("a").Each(func(i int, s *goquery.Selection) {
		href, exists := s.Attr("href")
		if exists && strings.HasSuffix(href, ".tar.gz") && strings.HasPrefix(href, "openssh-") {
			tarFiles = append(tarFiles, href)
		}
	})

	if len(tarFiles) == 0 {
		return nil, fmt.Errorf("未找到OpenSSH压缩包文件")
	}

	zap.L().Info("找到OpenSSH压缩包文件", zap.Int("count", len(tarFiles)))

	// 提取版本号并排序
	var versions []VersionInfo
	versionRegex := regexp.MustCompile(`^openssh-(\d+\.\d+p\d+)\.tar\.gz$`)

	for _, filename := range tarFiles {
		matches := versionRegex.FindStringSubmatch(filename)
		if len(matches) == 2 {
			versionStr := matches[1]
			// 使用标准库安全拼接URL
			downloadURL, err := url.JoinPath(d.mirrorURL, filename)
			if err != nil {
				continue // 如果URL拼接失败，跳过此文件
			}
			versions = append(versions, VersionInfo{
				Version:     versionStr,
				DownloadURL: downloadURL,
				Filename:    filename,
			})
		}
	}

	if len(versions) == 0 {
		return nil, fmt.Errorf("未找到有效的OpenSSH版本")
	}

	// 按版本号排序（从高到低）
	sort.Slice(versions, func(i, j int) bool {
		return compareVersions(versions[i].Version, versions[j].Version) > 0
	})

	latestVersion := versions[0]
	zap.L().Info("检测到最新OpenSSH版本", zap.String("version", latestVersion.Version))

	return &latestVersion, nil
}

// CheckCurrentVersion 检查当前系统安装的OpenSSH版本
// 示例值: 无参数
func (d *Detector) CheckCurrentVersion() (string, error) {
	zap.L().Info("检查当前系统OpenSSH版本")

	// 执行ssh -V命令
	cmd := exec.Command("ssh", "-V")
	output, err := cmd.CombinedOutput()
	if err != nil {
		return "", fmt.Errorf("执行ssh -V命令失败: %v", err)
	}

	// 从输出中提取版本号
	versionRegex := regexp.MustCompile(`OpenSSH_(\d+\.\d+p\d+)`)
	matches := versionRegex.FindStringSubmatch(string(output))
	
	if len(matches) == 2 {
		currentVersion := matches[1]
		zap.L().Info("当前OpenSSH版本", zap.String("version", currentVersion))
		return currentVersion, nil
	}

	return "", fmt.Errorf("无法从ssh -V输出中提取版本号")
}

// compareVersions 比较两个版本号
// 示例值: v1="9.7p1", v2="9.6p1"
func compareVersions(v1, v2 string) int {
	// 将版本号转换为可比较的格式
	v1Parts := parseVersion(v1)
	v2Parts := parseVersion(v2)

	// 比较主版本号
	for i := 0; i < len(v1Parts) && i < len(v2Parts); i++ {
		if v1Parts[i] > v2Parts[i] {
			return 1
		} else if v1Parts[i] < v2Parts[i] {
			return -1
		}
	}

	// 如果前面的部分都相同，长度更长的版本号更大
	if len(v1Parts) > len(v2Parts) {
		return 1
	} else if len(v1Parts) < len(v2Parts) {
		return -1
	}

	return 0
}

// parseVersion 解析版本号为数字数组
// 示例值: version="9.7p1"
func parseVersion(version string) []int {
	// 将版本号拆分为数字部分
	parts := strings.Split(strings.ReplaceAll(version, "p", "."), ".")
	var result []int

	for _, part := range parts {
		if num, err := strconv.Atoi(part); err == nil {
			result = append(result, num)
		}
	}

	return result
}

// CheckMirrorAvailability 检查镜像地址可用性
// 示例值: mirrorURL="https://mirrors.aliyun.com/openssh/portable/"
func (d *Detector) CheckMirrorAvailability() bool {
	zap.L().Info("检查镜像地址可用性", zap.String("mirrorURL", d.mirrorURL))

	req, err := http.NewRequest("HEAD", d.mirrorURL, nil)
	if err != nil {
		zap.S().Errorf("创建HEAD请求失败: %v", err)
		return false
	}

	req.Header.Set("User-Agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36")

	resp, err := d.client.Do(req)
	if err != nil {
		zap.S().Errorf("镜像地址不可达: %v", err)
		return false
	}
	defer resp.Body.Close()

	if resp.StatusCode == http.StatusOK {
		zap.L().Info("镜像地址检测通过")
		return true
	}

	zap.S().Errorf("镜像地址返回异常状态码: %d", resp.StatusCode)
	return false
}

// GetVersionList 获取所有可用版本列表
// 示例值: 无参数
func (d *Detector) GetVersionList() ([]VersionInfo, error) {
	zap.L().Info("获取OpenSSH所有可用版本列表")

	latestVersion, err := d.GetLatestVersion()
	if err != nil {
		return nil, err
	}

	// 这里可以扩展为获取所有版本，目前只返回最新版本
	return []VersionInfo{*latestVersion}, nil
}

// IsNewVersionAvailable 检查是否有新版本可用
// 示例值: currentVersion="9.6p1"
func (d *Detector) IsNewVersionAvailable(currentVersion string) (bool, *VersionInfo, error) {
	latestVersion, err := d.GetLatestVersion()
	if err != nil {
		return false, nil, err
	}

	if compareVersions(latestVersion.Version, currentVersion) > 0 {
		zap.L().Info("检测到新版本", zap.String("newVersion", latestVersion.Version), zap.String("currentVersion", currentVersion))
		return true, latestVersion, nil
	}

	zap.L().Info("当前已是最新版本")
	return false, latestVersion, nil
}